﻿
#include "Node.h"
#include "NodeEntity.h"

CNode::CNode()
{
	construct();
}

CNode::CNode(LPCTSTR strNodeType, LPCTSTR strText, COLORREF crColor, int iFontSize)
{
	construct();
	lstrcpy(m_strNodeType, strNodeType);
	lstrcpy(m_strText, strText);
	m_crColor = crColor;
	m_lf.lfHeight = -iFontSize;
	lstrcpy(m_lf.lfFaceName, GetFaceNameByNodeType(m_strNodeType));
	if (!_tcscmp(m_strNodeType, NT_GREEKALPHABET)) m_lf.lfItalic = TRUE;
	InitTEXTMERTIC();
	m_iFontSize = AdjustFontSize(m_strText, m_lf.lfFaceName, -m_lf.lfHeight, m_btmInternalLeading, m_btmDescent);

	UpdateTextSize();
	m_ptBaseline.y += m_tm.tmAscent;
}

CNode::~CNode()
{
	if (m_pLeftChild)
		delete m_pLeftChild;
	if (m_pRightChild)
		delete m_pRightChild;
}

CNode::CNode(const CNode& src) : m_pLeftChild(NULL), m_pRightChild(NULL), m_pParent(NULL)
{
	m_bEditMode = src.m_bEditMode;
	m_bDelMode = src.m_bDelMode;
	m_bLeftPart = src.m_bLeftPart;
	m_bRightPart = src.m_bRightPart;
	_tcscpy(m_strNodeType, src.m_strNodeType);
	_tcscpy(m_strText, src.m_strText);
	m_crColor = src.m_crColor;

	::ZeroMemory(&m_lf, sizeof(m_lf));
	::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &m_lf);
	_tcsncpy(m_lf.lfFaceName, src.m_lf.lfFaceName, LF_FACESIZE);
	m_lf.lfHeight = src.m_lf.lfHeight;
	m_lf.lfWidth = src.m_lf.lfWidth;
	m_lf.lfWeight = src.m_lf.lfWeight;
	m_lf.lfItalic = src.m_lf.lfItalic;
	m_lf.lfUnderline = src.m_lf.lfUnderline;
	m_lf.lfCharSet = src.m_lf.lfCharSet;

	m_szText = src.m_szText;
	m_rcNode = src.m_rcNode;
	m_iFontSize = src.m_iFontSize;
	m_btmInternalLeading = src.m_btmInternalLeading;
	m_btmDescent = src.m_btmDescent;
	m_tm = src.m_tm;
	m_ptBaseline = src.m_ptBaseline;
	m_iMinWidth = src.m_iMinWidth;
	m_iLeftChildMinWidth = src.m_iLeftChildMinWidth;
	m_iRightChildMinWidth = src.m_iRightChildMinWidth;

	if (src.m_pLeftChild) {
		m_pLeftChild = dynamicCopyNode(*src.m_pLeftChild);
		m_pLeftChild->m_pParent = this;
	}
	if (src.m_pRightChild) {
		m_pRightChild = dynamicCopyNode(*src.m_pRightChild);
		m_pRightChild->m_pParent = this;
	}
}

CNode& CNode::operator=(const CNode& other)
{
	if (this != &other) {
		m_bEditMode = other.m_bEditMode;
		m_bDelMode = other.m_bDelMode;
		m_bLeftPart = other.m_bLeftPart;
		m_bRightPart = other.m_bRightPart;
		_tcscpy(m_strNodeType, other.m_strNodeType);
		_tcscpy(m_strText, other.m_strText);
		m_crColor = other.m_crColor;

		::ZeroMemory(&m_lf, sizeof(m_lf));
		::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &m_lf);
		_tcsncpy(m_lf.lfFaceName, other.m_lf.lfFaceName, LF_FACESIZE);
		m_lf.lfHeight = other.m_lf.lfHeight;
		m_lf.lfWidth = other.m_lf.lfWidth;
		m_lf.lfWeight = other.m_lf.lfWeight;
		m_lf.lfItalic = other.m_lf.lfItalic;
		m_lf.lfUnderline = other.m_lf.lfUnderline;
		m_lf.lfCharSet = other.m_lf.lfCharSet;

		m_szText = other.m_szText;
		m_rcNode = other.m_rcNode;
		m_iFontSize = other.m_iFontSize;
		m_btmInternalLeading = other.m_btmInternalLeading;
		m_btmDescent = other.m_btmDescent;
		m_tm = other.m_tm;
		m_ptBaseline = other.m_ptBaseline;
		m_iMinWidth = other.m_iMinWidth;
		m_iLeftChildMinWidth = other.m_iLeftChildMinWidth;
		m_iRightChildMinWidth = other.m_iRightChildMinWidth;

		if (m_pLeftChild)
			delete m_pLeftChild;
		if (m_pRightChild)
			delete m_pRightChild;
		if (other.m_pLeftChild) {
			m_pLeftChild = dynamicCopyNode(*other.m_pLeftChild);
			m_pLeftChild->m_pParent = this;
		}
		if (other.m_pRightChild) {
			m_pRightChild = dynamicCopyNode(*other.m_pRightChild);
			m_pRightChild->m_pParent = this;
		}
	}
	return *this;
}

bool CNode::operator== (const CNode& other)
{
	return (!_tcscmp(m_strNodeType, other.m_strNodeType) && !_tcscmp(m_strText, other.m_strText)) && m_pLeftChild == other.m_pLeftChild && m_pRightChild == other.m_pRightChild;
}

CNode* CNode::dynamicCopyNode(const CNode& other)
{
	CNode* pNode = NULL;
	if (!_tcscmp(other.m_strNodeType, NT_STANDARD))
		pNode = new CEditNode(dynamic_cast<const CEditNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_INPLACE) ||
		!_tcscmp(other.m_strNodeType, NT_SIGN) ||
		!_tcscmp(other.m_strNodeType, NT_GREEKALPHABET) ||
		!_tcscmp(other.m_strNodeType, NT_ALPHABET) ||
		!_tcscmp(other.m_strNodeType, NT_HANDWRITING) ||
		!_tcscmp(other.m_strNodeType, NT_COPPERPLATE) ||
		!_tcscmp(other.m_strNodeType, NT_PLUS) ||
		!_tcscmp(other.m_strNodeType, NT_MINUS) ||
		!_tcscmp(other.m_strNodeType, NT_MULTIPLY) ||
		!_tcscmp(other.m_strNodeType, NT_DIVIDE) ||
		!_tcscmp(other.m_strNodeType, NT_EQUATION) ||
		!_tcscmp(other.m_strNodeType, NT_HYPHEN) ||
		!_tcscmp(other.m_strNodeType, NT_DOT) ||
		!_tcscmp(other.m_strNodeType, NT_LESSTHANOREQUAL) ||
		!_tcscmp(other.m_strNodeType, NT_GREATERTHANOREQUAL) ||
		!_tcscmp(other.m_strNodeType, NT_EQUAL) ||
		!_tcscmp(other.m_strNodeType, NT_LESSTHAN) ||
		!_tcscmp(other.m_strNodeType, NT_GREATERTHAN) ||
		!_tcscmp(other.m_strNodeType, NT_NOTEQUAL) ||
		!_tcscmp(other.m_strNodeType, NT_PERCENT) ||
		!_tcscmp(other.m_strNodeType, NT_SLASH) ||
		!_tcscmp(other.m_strNodeType, NT_BACKSLASH) ||
		!_tcscmp(other.m_strNodeType, NT_SINGLEQUOTE) ||
		!_tcscmp(other.m_strNodeType, NT_COLON) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLEQUOTE) ||
		!_tcscmp(other.m_strNodeType, NT_AND) ||
		!_tcscmp(other.m_strNodeType, NT_STAR) ||
		!_tcscmp(other.m_strNodeType, NT_HASHKEY) ||
		!_tcscmp(other.m_strNodeType, NT_QUESTIONMARK) ||
		!_tcscmp(other.m_strNodeType, NT_SEMICOLON) ||
		!_tcscmp(other.m_strNodeType, NT_VERTICALBAR) ||
		!_tcscmp(other.m_strNodeType, NT_EXCLAMATIONMARK) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTPARENTHESIS) ||
		!_tcscmp(other.m_strNodeType, NT_RIGHTPARENTHESIS) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTBRACKET) ||
		!_tcscmp(other.m_strNodeType, NT_RIGHTBRACKET) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTBRACE) ||
		!_tcscmp(other.m_strNodeType, NT_RIGHTBRACE) ||
		!_tcscmp(other.m_strNodeType, NT_TILDE) ||
		!_tcscmp(other.m_strNodeType, NT_PERIOD) ||
		!_tcscmp(other.m_strNodeType, NT_ISEQUIVALENTTO) ||
		!_tcscmp(other.m_strNodeType, NT_PLUSORMINUS) ||
		!_tcscmp(other.m_strNodeType, NT_COMMA) ||
		!_tcscmp(other.m_strNodeType, NT_ISAPPROXIMATELYEQUALTO) ||
		!_tcscmp(other.m_strNodeType, NT_INFINITY) ||
		!_tcscmp(other.m_strNodeType, NT_SINGLERIGHTARROW) ||
		!_tcscmp(other.m_strNodeType, NT_SINCE) ||
		!_tcscmp(other.m_strNodeType, NT_HENCE) ||
		!_tcscmp(other.m_strNodeType, NT_BELONGTO) ||
		!_tcscmp(other.m_strNodeType, NT_CONTAIN) ||
		!_tcscmp(other.m_strNodeType, NT_INCLUSION) ||
		!_tcscmp(other.m_strNodeType, NT_UNIONOF) ||
		!_tcscmp(other.m_strNodeType, NT_INTERSECTIONOF) ||
		!_tcscmp(other.m_strNodeType, NT_DELTA) ||
		!_tcscmp(other.m_strNodeType, NT_NABLA) ||
		!_tcscmp(other.m_strNodeType, NT_VARIESAS) ||
		!_tcscmp(other.m_strNodeType, NT_PROPOSITIONALNEGATION) ||
		!_tcscmp(other.m_strNodeType, NT_UNIVERSALQUANTIFIER) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLERIGHTARROW) ||
		!_tcscmp(other.m_strNodeType, NT_EXISTENTIALQUANTIFIER) ||
		!_tcscmp(other.m_strNodeType, NT_PLANCKCONSTANT) ||
		!_tcscmp(other.m_strNodeType, NT_LIM) ||
		!_tcscmp(other.m_strNodeType, NT_MIN) ||
		!_tcscmp(other.m_strNodeType, NT_MAX) ||
		!_tcscmp(other.m_strNodeType, NT_LOG) ||
		!_tcscmp(other.m_strNodeType, NT_LN) ||
		!_tcscmp(other.m_strNodeType, NT_LG) ||
		!_tcscmp(other.m_strNodeType, NT_NOTIN) ||
		!_tcscmp(other.m_strNodeType, NT_NSUBSETEQ) ||
		!_tcscmp(other.m_strNodeType, NT_EMPTYSET) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTRIGHTARROW) ||
		!_tcscmp(other.m_strNodeType, NT_MAPSTO) ||
		!_tcscmp(other.m_strNodeType, NT_epsilon) ||
		!_tcscmp(other.m_strNodeType, NT_ALEPH) ||
		!_tcscmp(other.m_strNodeType, NT_varrho) ||
		!_tcscmp(other.m_strNodeType, NT_BOXMINUS) ||
		!_tcscmp(other.m_strNodeType, NT_BOXTIMES) ||
		!_tcscmp(other.m_strNodeType, NT_BOXDOT) ||
		!_tcscmp(other.m_strNodeType, NT_BOXPLUS) ||
		!_tcscmp(other.m_strNodeType, NT_OMINUS) ||
		!_tcscmp(other.m_strNodeType, NT_CIRCLEDDASH) ||
		!_tcscmp(other.m_strNodeType, NT_OPLUS) ||
		!_tcscmp(other.m_strNodeType, NT_OTIMES) ||
		!_tcscmp(other.m_strNodeType, NT_OSLASH) ||
		!_tcscmp(other.m_strNodeType, NT_ODOT) ||
		!_tcscmp(other.m_strNodeType, NT_CIRCLEDCIRC) ||
		!_tcscmp(other.m_strNodeType, NT_CIRCLEDAST) ||
		!_tcscmp(other.m_strNodeType, NT_BIGODOT) ||
		!_tcscmp(other.m_strNodeType, NT_BIGOTIMES) ||
		!_tcscmp(other.m_strNodeType, NT_BIGOPLUS) ||
		!_tcscmp(other.m_strNodeType, NT_INTEGRAL) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLEINTEGRAL) ||
		!_tcscmp(other.m_strNodeType, NT_TRIPLEINTEGRAL) ||
		!_tcscmp(other.m_strNodeType, NT_LOOPINTEGRAL) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLELOOPINTEGRAL) ||
		!_tcscmp(other.m_strNodeType, NT_TRIPLELOOPINTEGRAL) ||
		!_tcscmp(other.m_strNodeType, NT_SUM) ||
		!_tcscmp(other.m_strNodeType, NT_SUPREMUM) ||
		!_tcscmp(other.m_strNodeType, NT_INFIMUM) ||
		!_tcscmp(other.m_strNodeType, NT_PRODUCT) ||
		!_tcscmp(other.m_strNodeType, NT_ACCESSORYPRODUCT) ||
		!_tcscmp(other.m_strNodeType, NT_UNION) ||
		!_tcscmp(other.m_strNodeType, NT_INTERSECTION) ||
		!_tcscmp(other.m_strNodeType, NT_SIN) ||
		!_tcscmp(other.m_strNodeType, NT_COS) ||
		!_tcscmp(other.m_strNodeType, NT_TAN) ||
		!_tcscmp(other.m_strNodeType, NT_CSC) ||
		!_tcscmp(other.m_strNodeType, NT_SEC) ||
		!_tcscmp(other.m_strNodeType, NT_COT) ||
		!_tcscmp(other.m_strNodeType, NT_ARCSIN) ||
		!_tcscmp(other.m_strNodeType, NT_ARCCOS) ||
		!_tcscmp(other.m_strNodeType, NT_ARCTAN) ||
		!_tcscmp(other.m_strNodeType, NT_SINH) ||
		!_tcscmp(other.m_strNodeType, NT_COSH) ||
		!_tcscmp(other.m_strNodeType, NT_TANH) ||
		!_tcscmp(other.m_strNodeType, NT_COTH) ||
		!_tcscmp(other.m_strNodeType, NT_ARG) ||
		!_tcscmp(other.m_strNodeType, NT_DEG) ||
		!_tcscmp(other.m_strNodeType, NT_DET) ||
		!_tcscmp(other.m_strNodeType, NT_DIM) ||
		!_tcscmp(other.m_strNodeType, NT_EXP) ||
		!_tcscmp(other.m_strNodeType, NT_GCD) ||
		!_tcscmp(other.m_strNodeType, NT_HOM) ||
		!_tcscmp(other.m_strNodeType, NT_KER) ||
		!_tcscmp(other.m_strNodeType, NT_PR) ||
		!_tcscmp(other.m_strNodeType, NT_LIMINF) ||
		!_tcscmp(other.m_strNodeType, NT_LIMSUP))
		pNode = new COperatorNode(dynamic_cast<const COperatorNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_LIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_MINIMUM) ||
		!_tcscmp(other.m_strNodeType, NT_MAXIMUM))
		pNode = new CLimitedNode(dynamic_cast<const CLimitedNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_LOGARITHM))
		pNode = new CLogarithmNode(dynamic_cast<const CLogarithmNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_SUPERSCRIPT))
		pNode = new CSuperscriptNode(dynamic_cast<const CSuperscriptNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_SUBSCRIPT))
		pNode = new CSubscriptNode(dynamic_cast<const CSubscriptNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_MIDTOPBOTTOM))
		pNode = new CMidTopBottomLayoutNode(dynamic_cast<const CMidTopBottomLayoutNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_TOPBOTTOMMID))
		pNode = new CTopBottomMidLayoutNode(dynamic_cast<const CTopBottomMidLayoutNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_RADICAL))
		pNode = new CRadicalNode(dynamic_cast<const CRadicalNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_PARENTHESES) ||
		!_tcscmp(other.m_strNodeType, NT_BRACKETS) ||
		!_tcscmp(other.m_strNodeType, NT_BRACES) ||
		!_tcscmp(other.m_strNodeType, NT_ABSOLUTE))
		pNode = new CBracketsNode(dynamic_cast<const CBracketsNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_SEPARATOR))
		pNode = new CSeparatorNode(dynamic_cast<const CSeparatorNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_INTEGRALTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLEINTEGRALTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_TRIPLEINTEGRALTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_LOOPINTEGRALTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLELOOPINTEGRALTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_TRIPLELOOPINTEGRALTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_SUMTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_SUPREMUMTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_INFIMUMTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_PRODUCTTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_ACCESSORYPRODUCTTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_UNIONTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_INTERSECTIONTBLIMIT))
		pNode = new CTopMidBottomLargeOperatorNode(dynamic_cast<const CTopMidBottomLargeOperatorNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_INTEGRALTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLEINTEGRALTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_TRIPLEINTEGRALTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_LOOPINTEGRALTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_DOUBLELOOPINTEGRALTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_TRIPLELOOPINTEGRALTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_SUMTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_SUPREMUMTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_INFIMUMTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_PRODUCTTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_ACCESSORYPRODUCTTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_UNIONTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_INTERSECTIONTBSCRIPT))
		pNode = new CMidTopBottomLargeOperatorNode(dynamic_cast<const CMidTopBottomLargeOperatorNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_SUMBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_SUPREMUMBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_INFIMUMBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_PRODUCTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_ACCESSORYPRODUCTBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_UNIONBLIMIT) ||
		!_tcscmp(other.m_strNodeType, NT_INTERSECTIONBLIMIT))
		pNode = new CMidBottomLargeOperatorNode(dynamic_cast<const CMidBottomLargeOperatorNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_SUMBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_SUPREMUMBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_INFIMUMBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_PRODUCTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_ACCESSORYPRODUCTBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_UNIONBSCRIPT) ||
		!_tcscmp(other.m_strNodeType, NT_INTERSECTIONBSCRIPT))
		pNode = new CMidRightBottomLargeOperatorNode(dynamic_cast<const CMidRightBottomLargeOperatorNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_TOPBOTTOM))
		pNode = new CTopBottomNode(dynamic_cast<const CTopBottomNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_LINE))
		pNode = new CLineNode(dynamic_cast<const CLineNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_FRACTION))
		pNode = new CFractionalNode(dynamic_cast<const CFractionalNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_HORIZONTALMATRIX))
		pNode = new CHorizontalMatrix(dynamic_cast<const CHorizontalMatrix&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_VERTICALMATRIX))
		pNode = new CVerticalMatrix(dynamic_cast<const CVerticalMatrix&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_RIGHTSINGLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTSINGLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TWOWAYSINGLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_RIGHTHALFARROW) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTHALFARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TWOWAYHALFARROW) ||
		!_tcscmp(other.m_strNodeType, NT_RIGHTDOUBLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_LEFTDOUBLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TWOWAYDOUBLEARROW))
		pNode = new CArrowNode(dynamic_cast<const CArrowNode&>(other));
	else if (!_tcscmp(other.m_strNodeType, NT_TOPRIGHTSINGLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TOPLEFTSINGLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TOPRIGHTHALFARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TOPLEFTHALFARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TOPTWOWAYSINGLEARROW) ||
		!_tcscmp(other.m_strNodeType, NT_TOPONEPOINT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPTWOPOINT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPTHREEPOINT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPONELINE) ||
		!_tcscmp(other.m_strNodeType, NT_TOPTWOLINE) ||
		!_tcscmp(other.m_strNodeType, NT_TOPACUTEACCENT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPGRAVEACCENT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPCIRCUMFLEXACCENT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPMODULATEACCENT) ||
		!_tcscmp(other.m_strNodeType, NT_TOPTILDE) ||
		!_tcscmp(other.m_strNodeType, NT_TOPBREVEACCENT))
		pNode = new CTaggedSignNode(dynamic_cast<const CTaggedSignNode&>(other));
	//else
	//	pNode = new CNode(other);
	return pNode;
}

CNode* CNode::dynamicCreateNode(LPCTSTR strNodeType, LPCTSTR strText)
{
	CNode* pNode = NULL;
	if (!_tcscmp(strNodeType, NT_STANDARD))
		pNode = new CEditNode(strNodeType, strText);
	else if (!_tcscmp(strNodeType, NT_SIGN) ||
		!_tcscmp(strNodeType, NT_GREEKALPHABET) ||
		!_tcscmp(strNodeType, NT_ALPHABET) ||
		!_tcscmp(strNodeType, NT_HANDWRITING) ||
		!_tcscmp(strNodeType, NT_COPPERPLATE))
		pNode = new COperatorNode(strNodeType, strText);
	else if (!_tcscmp(strNodeType, NT_INPLACE) ||
		!_tcscmp(strNodeType, NT_PLUS) ||
		!_tcscmp(strNodeType, NT_MINUS) ||
		!_tcscmp(strNodeType, NT_MULTIPLY) ||
		!_tcscmp(strNodeType, NT_DIVIDE) ||
		!_tcscmp(strNodeType, NT_EQUATION) ||
		!_tcscmp(strNodeType, NT_HYPHEN) ||
		!_tcscmp(strNodeType, NT_DOT) ||
		!_tcscmp(strNodeType, NT_LESSTHANOREQUAL) ||
		!_tcscmp(strNodeType, NT_GREATERTHANOREQUAL) ||
		!_tcscmp(strNodeType, NT_EQUAL) ||
		!_tcscmp(strNodeType, NT_LESSTHAN) ||
		!_tcscmp(strNodeType, NT_GREATERTHAN) ||
		!_tcscmp(strNodeType, NT_NOTEQUAL) ||
		!_tcscmp(strNodeType, NT_PERCENT) ||
		!_tcscmp(strNodeType, NT_SLASH) ||
		!_tcscmp(strNodeType, NT_BACKSLASH) ||
		!_tcscmp(strNodeType, NT_SINGLEQUOTE) ||
		!_tcscmp(strNodeType, NT_COLON) ||
		!_tcscmp(strNodeType, NT_DOUBLEQUOTE) ||
		!_tcscmp(strNodeType, NT_AND) ||
		!_tcscmp(strNodeType, NT_STAR) ||
		!_tcscmp(strNodeType, NT_HASHKEY) ||
		!_tcscmp(strNodeType, NT_QUESTIONMARK) ||
		!_tcscmp(strNodeType, NT_SEMICOLON) ||
		!_tcscmp(strNodeType, NT_VERTICALBAR) ||
		!_tcscmp(strNodeType, NT_EXCLAMATIONMARK) ||
		!_tcscmp(strNodeType, NT_LEFTPARENTHESIS) ||
		!_tcscmp(strNodeType, NT_RIGHTPARENTHESIS) ||
		!_tcscmp(strNodeType, NT_LEFTBRACKET) ||
		!_tcscmp(strNodeType, NT_RIGHTBRACKET) ||
		!_tcscmp(strNodeType, NT_LEFTBRACE) ||
		!_tcscmp(strNodeType, NT_RIGHTBRACE) ||
		!_tcscmp(strNodeType, NT_TILDE) ||
		!_tcscmp(strNodeType, NT_PERIOD) ||
		!_tcscmp(strNodeType, NT_ISEQUIVALENTTO) ||
		!_tcscmp(strNodeType, NT_PLUSORMINUS) ||
		!_tcscmp(strNodeType, NT_COMMA) ||
		!_tcscmp(strNodeType, NT_ISAPPROXIMATELYEQUALTO) ||
		!_tcscmp(strNodeType, NT_INFINITY) ||
		!_tcscmp(strNodeType, NT_SINGLERIGHTARROW) ||
		!_tcscmp(strNodeType, NT_SINCE) ||
		!_tcscmp(strNodeType, NT_HENCE) ||
		!_tcscmp(strNodeType, NT_BELONGTO) ||
		!_tcscmp(strNodeType, NT_CONTAIN) ||
		!_tcscmp(strNodeType, NT_INCLUSION) ||
		!_tcscmp(strNodeType, NT_UNIONOF) ||
		!_tcscmp(strNodeType, NT_INTERSECTIONOF) ||
		!_tcscmp(strNodeType, NT_DELTA) ||
		!_tcscmp(strNodeType, NT_NABLA) ||
		!_tcscmp(strNodeType, NT_VARIESAS) ||
		!_tcscmp(strNodeType, NT_PROPOSITIONALNEGATION) ||
		!_tcscmp(strNodeType, NT_UNIVERSALQUANTIFIER) ||
		!_tcscmp(strNodeType, NT_DOUBLERIGHTARROW) ||
		!_tcscmp(strNodeType, NT_EXISTENTIALQUANTIFIER) ||
		!_tcscmp(strNodeType, NT_PLANCKCONSTANT) ||
		!_tcscmp(strNodeType, NT_LIM) ||
		!_tcscmp(strNodeType, NT_MIN) ||
		!_tcscmp(strNodeType, NT_MAX) ||
		!_tcscmp(strNodeType, NT_LOG) ||
		!_tcscmp(strNodeType, NT_LN) ||
		!_tcscmp(strNodeType, NT_LG) ||
		!_tcscmp(strNodeType, NT_NOTIN) ||
		!_tcscmp(strNodeType, NT_NSUBSETEQ) ||
		!_tcscmp(strNodeType, NT_EMPTYSET) ||
		!_tcscmp(strNodeType, NT_LEFTRIGHTARROW) ||
		!_tcscmp(strNodeType, NT_MAPSTO) ||
		!_tcscmp(strNodeType, NT_epsilon) ||
		!_tcscmp(strNodeType, NT_ALEPH) ||
		!_tcscmp(strNodeType, NT_varrho) ||
		!_tcscmp(strNodeType, NT_BOXMINUS) ||
		!_tcscmp(strNodeType, NT_BOXTIMES) ||
		!_tcscmp(strNodeType, NT_BOXDOT) ||
		!_tcscmp(strNodeType, NT_BOXPLUS) ||
		!_tcscmp(strNodeType, NT_OMINUS) ||
		!_tcscmp(strNodeType, NT_CIRCLEDDASH) ||
		!_tcscmp(strNodeType, NT_OPLUS) ||
		!_tcscmp(strNodeType, NT_OTIMES) ||
		!_tcscmp(strNodeType, NT_OSLASH) ||
		!_tcscmp(strNodeType, NT_ODOT) ||
		!_tcscmp(strNodeType, NT_CIRCLEDCIRC) ||
		!_tcscmp(strNodeType, NT_CIRCLEDAST) ||
		!_tcscmp(strNodeType, NT_BIGODOT) ||
		!_tcscmp(strNodeType, NT_BIGOTIMES) ||
		!_tcscmp(strNodeType, NT_BIGOPLUS) ||
		!_tcscmp(strNodeType, NT_INTEGRAL) ||
		!_tcscmp(strNodeType, NT_DOUBLEINTEGRAL) ||
		!_tcscmp(strNodeType, NT_TRIPLEINTEGRAL) ||
		!_tcscmp(strNodeType, NT_LOOPINTEGRAL) ||
		!_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRAL) ||
		!_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRAL) ||
		!_tcscmp(strNodeType, NT_SUM) ||
		!_tcscmp(strNodeType, NT_SUPREMUM) ||
		!_tcscmp(strNodeType, NT_INFIMUM) ||
		!_tcscmp(strNodeType, NT_PRODUCT) ||
		!_tcscmp(strNodeType, NT_ACCESSORYPRODUCT) ||
		!_tcscmp(strNodeType, NT_UNION) ||
		!_tcscmp(strNodeType, NT_INTERSECTION) ||
		!_tcscmp(strNodeType, NT_SIN) ||
		!_tcscmp(strNodeType, NT_COS) ||
		!_tcscmp(strNodeType, NT_TAN) ||
		!_tcscmp(strNodeType, NT_CSC) ||
		!_tcscmp(strNodeType, NT_SEC) ||
		!_tcscmp(strNodeType, NT_COT) ||
		!_tcscmp(strNodeType, NT_ARCSIN) ||
		!_tcscmp(strNodeType, NT_ARCCOS) ||
		!_tcscmp(strNodeType, NT_ARCTAN) ||
		!_tcscmp(strNodeType, NT_SINH) ||
		!_tcscmp(strNodeType, NT_COSH) ||
		!_tcscmp(strNodeType, NT_TANH) ||
		!_tcscmp(strNodeType, NT_COTH) ||
		!_tcscmp(strNodeType, NT_ARG) ||
		!_tcscmp(strNodeType, NT_DEG) ||
		!_tcscmp(strNodeType, NT_DET) ||
		!_tcscmp(strNodeType, NT_DIM) ||
		!_tcscmp(strNodeType, NT_EXP) ||
		!_tcscmp(strNodeType, NT_GCD) ||
		!_tcscmp(strNodeType, NT_HOM) ||
		!_tcscmp(strNodeType, NT_KER) ||
		!_tcscmp(strNodeType, NT_PR) ||
		!_tcscmp(strNodeType, NT_LIMINF) ||
		!_tcscmp(strNodeType, NT_LIMSUP))
		pNode = new COperatorNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_LIMIT) ||
		!_tcscmp(strNodeType, NT_MINIMUM) ||
		!_tcscmp(strNodeType, NT_MAXIMUM))
		pNode = new CLimitedNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_LOGARITHM))
		pNode = new CLogarithmNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_SUPERSCRIPT))
		pNode = new CSuperscriptNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_SUBSCRIPT))
		pNode = new CSubscriptNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_MIDTOPBOTTOM))
		pNode = new CMidTopBottomLayoutNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_TOPBOTTOMMID))
		pNode = new CTopBottomMidLayoutNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_RADICAL))
		pNode = new CRadicalNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_PARENTHESES) ||
		!_tcscmp(strNodeType, NT_BRACKETS) ||
		!_tcscmp(strNodeType, NT_BRACES) ||
		!_tcscmp(strNodeType, NT_ABSOLUTE))
		pNode = new CBracketsNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_SEPARATOR))
		pNode = new CSeparatorNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_INTEGRALTBLIMIT) ||
		!_tcscmp(strNodeType, NT_DOUBLEINTEGRALTBLIMIT) ||
		!_tcscmp(strNodeType, NT_TRIPLEINTEGRALTBLIMIT) ||
		!_tcscmp(strNodeType, NT_LOOPINTEGRALTBLIMIT) ||
		!_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRALTBLIMIT) ||
		!_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRALTBLIMIT) ||
		!_tcscmp(strNodeType, NT_SUMTBLIMIT) ||
		!_tcscmp(strNodeType, NT_SUPREMUMTBLIMIT) ||
		!_tcscmp(strNodeType, NT_INFIMUMTBLIMIT) ||
		!_tcscmp(strNodeType, NT_PRODUCTTBLIMIT) ||
		!_tcscmp(strNodeType, NT_ACCESSORYPRODUCTTBLIMIT) ||
		!_tcscmp(strNodeType, NT_UNIONTBLIMIT) ||
		!_tcscmp(strNodeType, NT_INTERSECTIONTBLIMIT))
		pNode = new CTopMidBottomLargeOperatorNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_INTEGRALTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_DOUBLEINTEGRALTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_TRIPLEINTEGRALTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_LOOPINTEGRALTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRALTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRALTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_SUMTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_SUPREMUMTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_INFIMUMTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_PRODUCTTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_ACCESSORYPRODUCTTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_UNIONTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_INTERSECTIONTBSCRIPT))
		pNode = new CMidTopBottomLargeOperatorNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_SUMBLIMIT) ||
		!_tcscmp(strNodeType, NT_SUPREMUMBLIMIT) ||
		!_tcscmp(strNodeType, NT_INFIMUMBLIMIT) ||
		!_tcscmp(strNodeType, NT_PRODUCTBLIMIT) ||
		!_tcscmp(strNodeType, NT_ACCESSORYPRODUCTBLIMIT) ||
		!_tcscmp(strNodeType, NT_UNIONBLIMIT) ||
		!_tcscmp(strNodeType, NT_INTERSECTIONBLIMIT))
		pNode = new CMidBottomLargeOperatorNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_SUMBSCRIPT) ||
		!_tcscmp(strNodeType, NT_SUPREMUMBSCRIPT) ||
		!_tcscmp(strNodeType, NT_INFIMUMBSCRIPT) ||
		!_tcscmp(strNodeType, NT_PRODUCTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_ACCESSORYPRODUCTBSCRIPT) ||
		!_tcscmp(strNodeType, NT_UNIONBSCRIPT) ||
		!_tcscmp(strNodeType, NT_INTERSECTIONBSCRIPT))
		pNode = new CMidRightBottomLargeOperatorNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_TOPBOTTOM))
		pNode = new CTopBottomNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_LINE))
		pNode = new CLineNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_FRACTION))
		pNode = new CFractionalNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_HORIZONTALMATRIX))
		pNode = new CHorizontalMatrix(strNodeType);
	else if (!_tcscmp(strNodeType, NT_VERTICALMATRIX))
		pNode = new CVerticalMatrix(strNodeType);
	else if (!_tcscmp(strNodeType, NT_RIGHTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_LEFTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TWOWAYSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_RIGHTHALFARROW) ||
		!_tcscmp(strNodeType, NT_LEFTHALFARROW) ||
		!_tcscmp(strNodeType, NT_TWOWAYHALFARROW) ||
		!_tcscmp(strNodeType, NT_RIGHTDOUBLEARROW) ||
		!_tcscmp(strNodeType, NT_LEFTDOUBLEARROW) ||
		!_tcscmp(strNodeType, NT_TWOWAYDOUBLEARROW))
		pNode = new CArrowNode(strNodeType);
	else if (!_tcscmp(strNodeType, NT_TOPRIGHTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TOPLEFTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TOPRIGHTHALFARROW) ||
		!_tcscmp(strNodeType, NT_TOPLEFTHALFARROW) ||
		!_tcscmp(strNodeType, NT_TOPTWOWAYSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TOPONEPOINT) ||
		!_tcscmp(strNodeType, NT_TOPTWOPOINT) ||
		!_tcscmp(strNodeType, NT_TOPTHREEPOINT) ||
		!_tcscmp(strNodeType, NT_TOPONELINE) ||
		!_tcscmp(strNodeType, NT_TOPTWOLINE) ||
		!_tcscmp(strNodeType, NT_TOPACUTEACCENT) ||
		!_tcscmp(strNodeType, NT_TOPGRAVEACCENT) ||
		!_tcscmp(strNodeType, NT_TOPCIRCUMFLEXACCENT) ||
		!_tcscmp(strNodeType, NT_TOPMODULATEACCENT) ||
		!_tcscmp(strNodeType, NT_TOPTILDE) ||
		!_tcscmp(strNodeType, NT_TOPBREVEACCENT))
		pNode = new CTaggedSignNode(strNodeType);
	//else
	//	pNode = new CNode();
	return pNode;
}

void CNode::construct()
{
	m_pParent = NULL;
	m_pLeftChild = NULL;
	m_pRightChild = NULL;

	m_bEditMode = true;
	m_bDelMode = true;
	m_bLeftPart = true;
	m_bRightPart = true;

	::ZeroMemory(&m_strNodeType, sizeof(m_strNodeType));
	::ZeroMemory(&m_strText, sizeof(m_strText));

	m_crColor = kNodeColor;// ::GetSysColor(COLOR_WINDOWTEXT);
	
	::ZeroMemory(&m_lf, sizeof(m_lf));
	::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &m_lf);
	_tcsncpy(m_lf.lfFaceName, kFontFamily, LF_FACESIZE);
	m_lf.lfCharSet = DEFAULT_CHARSET;
	m_lf.lfHeight = 0 - kFontSize;
	//m_lf.lfWidth = 0;
	//m_lf.lfEscapement = 0;
	//m_lf.lfOrientation = 0;
	//m_lf.lfWeight = FW_NORMAL;
	//m_lf.lfItalic = FALSE;
	//m_lf.lfUnderline = FALSE;
	//m_lf.lfStrikeOut = FALSE;
	//m_lf.lfCharSet = DEFAULT_CHARSET;// ANSI_CHARSET;//GB2312_CHARSET;
	//m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
	//m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
	//m_lf.lfQuality = DEFAULT_QUALITY;
	//m_lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
	//lstrcpy(m_lf.lfFaceName, kFontFamily);

	::ZeroMemory(&m_szText, sizeof(m_szText));
	::ZeroMemory(&m_rcNode, sizeof(m_rcNode));
	m_iFontSize = kFontSize;
	m_btmInternalLeading = true;
	m_btmDescent = true;
	::ZeroMemory(&m_tm, sizeof(m_tm));
	m_ptBaseline = { 0,0 };
	m_iMinWidth = 1;
	m_iLeftChildMinWidth = m_iRightChildMinWidth = 2;
}

LPCTSTR CNode::GetNodeType()
{
	return m_strNodeType;
}

CNode* CNode::GetParentNode()
{
	return m_pParent;
}

void CNode::SetParentNode(CNode* pNode)
{
	m_pParent = pNode;
}

void CNode::SetLeftChild(CNode* pNode)
{
	m_pLeftChild = pNode;
	if (m_pLeftChild)
	{
		m_pLeftChild->m_pParent = this;
		if (!_tcscmp(m_pLeftChild->m_strNodeType, NT_STANDARD))
			m_pLeftChild->SetMinWidth(m_iLeftChildMinWidth);
	}
}

CNode* CNode::GetLeftChild()
{
	return m_pLeftChild;
}

void CNode::SetRightChild(CNode* pNode)
{
	m_pRightChild = pNode;
	if (m_pRightChild)
	{
		m_pRightChild->m_pParent = this;
		if (!_tcscmp(m_pRightChild->m_strNodeType, NT_STANDARD))
			m_pRightChild->SetMinWidth(m_iRightChildMinWidth);
	}
}

CNode* CNode::GetRightChild()
{
	return m_pRightChild;
}

bool CNode::IsLeftChild()
{
	bool lRet = false;
	if (m_pParent && m_pParent->m_pLeftChild == this)
		lRet = true;
	return lRet;
}

bool CNode::IsRightChild()
{
	bool lRet = false;
	if (m_pParent && m_pParent->m_pRightChild == this)
		lRet = true;
	return lRet;
}

CNode* CNode::GetBrotherNode()
{
	CNode* pRet = NULL;
	if (IsLeftChild())
		pRet = m_pParent->m_pRightChild;
	if (IsRightChild())
		pRet = m_pParent->m_pLeftChild;
	return pRet;
}

void CNode::SetText(LPCTSTR strText)
{
	lstrcpy(m_strText, strText);
	UpdateTextSize();
}

LPCTSTR CNode::GetText()
{
	return m_strText;
}

void CNode::SetEditMode(bool bEditMode)
{
	m_bEditMode = bEditMode;
}

bool CNode::GetEditMode()
{
	return m_bEditMode;
}

bool CNode::GetDelMode()
{
	return m_bDelMode;
}

void CNode::SetColor(COLORREF crColor)
{
	m_crColor = crColor;
}

COLORREF CNode::GetColor()
{
	return  m_crColor;
}

void CNode::ChangeColor(COLORREF crColor)
{
	if (m_pLeftChild)
		m_pLeftChild->ChangeColor(crColor);
	if (m_pRightChild)
		m_pRightChild->ChangeColor(crColor);
	m_crColor = crColor;
}

void CNode::SetMinWidth(int iMinWidth)
{
	m_iMinWidth = iMinWidth;
	if (lstrlen(m_strText) == 0 && m_szText.cx < m_iMinWidth)
		m_szText.cx = m_iMinWidth;
}

void CNode::SetFaceName(LPCTSTR strFaceName)
{
	lstrcpy(m_lf.lfFaceName, strFaceName);
}

LPCTSTR CNode::GetFaceName()
{
	return m_lf.lfFaceName;
}

LOGFONT* CNode::GetLogFont()
{
	return &m_lf;
}

void CNode::SetFontSize(int iFontSize)
{
	m_iFontSize = 0 - iFontSize;
}

int CNode::GetFontSize()
{
	return m_iFontSize;
}

void CNode::ChangeFontSize(int iFontSize)
{
	if (m_pLeftChild)
		m_pLeftChild->ChangeFontSize(iFontSize);
	if (m_pRightChild)
		m_pRightChild->ChangeFontSize(iFontSize);
	m_lf.lfHeight = -iFontSize;
	m_iFontSize = AdjustFontSize(m_strText, m_lf.lfFaceName, -m_lf.lfHeight, m_btmInternalLeading, m_btmDescent);
	UpdateTextSize();
}

BOOL CNode::IsNodeLeaf()
{
	if (GetLeftChild() || GetRightChild())
		return FALSE;
	else
		return TRUE;
}

RECT CNode::GetRect()
{
	return m_rcNode;
}

void CNode::SetRect(LPRECT lprc)
{
	m_rcNode.left = lprc->left;
	m_rcNode.top = lprc->top;
	m_rcNode.right = lprc->right;
	m_rcNode.bottom = lprc->bottom;
}

SIZE CNode::GetTextSize() const
{
	return m_szText;
}

POINT CNode::GetBaseline() const
{
	return m_ptBaseline;
}

LONG CNode::GetBaselineY() const
{
	return m_ptBaseline.y;
}

DWORD CNode::GetWidth() const
{
	return m_rcNode.right - m_rcNode.left;
}

DWORD CNode::GetHeight() const
{
	return m_rcNode.bottom - m_rcNode.top;
}

LPCTSTR GetOperatorTextByNodeType(LPCTSTR strNodeType)
{
	if (!_tcscmp(strNodeType, NT_PLUS)) return _T("+");
	else if (!_tcscmp(strNodeType, NT_MINUS)) return _T("-");
	else if (!_tcscmp(strNodeType, NT_MULTIPLY)) return _T("×");
	else if (!_tcscmp(strNodeType, NT_DIVIDE)) return _T("÷");
	else if (!_tcscmp(strNodeType, NT_EQUATION)) return _T("=");
	else if (!_tcscmp(strNodeType, NT_HYPHEN)) return _T("-");
	else if (!_tcscmp(strNodeType, NT_DOT)) return _T("·");
	else if (!_tcscmp(strNodeType, NT_LESSTHANOREQUAL)) return _T("≤");
	else if (!_tcscmp(strNodeType, NT_GREATERTHANOREQUAL)) return _T("≥");
	else if (!_tcscmp(strNodeType, NT_EQUAL)) return _T("=");
	else if (!_tcscmp(strNodeType, NT_LESSTHAN)) return _T("<");
	else if (!_tcscmp(strNodeType, NT_GREATERTHAN)) return _T(">");
	else if (!_tcscmp(strNodeType, NT_NOTEQUAL)) return _T("≠");
	else if (!_tcscmp(strNodeType, NT_PERCENT)) return _T("%");
	else if (!_tcscmp(strNodeType, NT_SLASH)) return _T("/");
	else if (!_tcscmp(strNodeType, NT_BACKSLASH)) return _T("\\");
	else if (!_tcscmp(strNodeType, NT_SINGLEQUOTE)) return _T("'");
	else if (!_tcscmp(strNodeType, NT_COLON)) return _T(":");
	else if (!_tcscmp(strNodeType, NT_DOUBLEQUOTE)) return _T("\"");
	else if (!_tcscmp(strNodeType, NT_AND)) return _T("&");
	else if (!_tcscmp(strNodeType, NT_STAR)) return _T("*");
	else if (!_tcscmp(strNodeType, NT_HASHKEY)) return _T("#");
	else if (!_tcscmp(strNodeType, NT_QUESTIONMARK)) return _T("?");
	else if (!_tcscmp(strNodeType, NT_SEMICOLON)) return _T(";");
	else if (!_tcscmp(strNodeType, NT_VERTICALBAR)) return _T("|");
	else if (!_tcscmp(strNodeType, NT_EXCLAMATIONMARK)) return _T("!");
	else if (!_tcscmp(strNodeType, NT_LEFTPARENTHESIS)) return _T("(");
	else if (!_tcscmp(strNodeType, NT_RIGHTPARENTHESIS)) return _T(")");
	else if (!_tcscmp(strNodeType, NT_LEFTBRACKET)) return _T("[");
	else if (!_tcscmp(strNodeType, NT_RIGHTBRACKET)) return _T("]");
	else if (!_tcscmp(strNodeType, NT_LEFTBRACE)) return _T("{");
	else if (!_tcscmp(strNodeType, NT_RIGHTBRACE)) return _T("}");
	else if (!_tcscmp(strNodeType, NT_TILDE)) return _T("~");
	else if (!_tcscmp(strNodeType, NT_PERIOD)) return _T(".");
	else if (!_tcscmp(strNodeType, NT_ISEQUIVALENTTO)) return _T("≡");
	else if (!_tcscmp(strNodeType, NT_PLUSORMINUS)) return _T("±");
	else if (!_tcscmp(strNodeType, NT_COMMA)) return _T(",");
	else if (!_tcscmp(strNodeType, NT_ISAPPROXIMATELYEQUALTO)) return _T("≈");
	else if (!_tcscmp(strNodeType, NT_INFINITY)) return _T("∞");
	else if (!_tcscmp(strNodeType, NT_SINGLERIGHTARROW)) return _T("→");
	else if (!_tcscmp(strNodeType, NT_SINCE)) return _T("∵");
	else if (!_tcscmp(strNodeType, NT_HENCE)) return _T("∴");
	else if (!_tcscmp(strNodeType, NT_BELONGTO)) return _T("∈");
	else if (!_tcscmp(strNodeType, NT_CONTAIN)) return _T("⊂");
	else if (!_tcscmp(strNodeType, NT_INCLUSION)) return _T("⊆");
	else if (!_tcscmp(strNodeType, NT_UNIONOF)) return _T("∪");
	else if (!_tcscmp(strNodeType, NT_INTERSECTIONOF)) return _T("∩");
	else if (!_tcscmp(strNodeType, NT_DELTA)) return _T("∂");
	else if (!_tcscmp(strNodeType, NT_NABLA)) return _T("▽");
	else if (!_tcscmp(strNodeType, NT_VARIESAS)) return _T("∝");
	else if (!_tcscmp(strNodeType, NT_PROPOSITIONALNEGATION)) return _T("﹁");
	else if (!_tcscmp(strNodeType, NT_UNIVERSALQUANTIFIER)) return _T("∀");
	else if (!_tcscmp(strNodeType, NT_DOUBLERIGHTARROW)) return _T("⇒");
	else if (!_tcscmp(strNodeType, NT_EXISTENTIALQUANTIFIER)) return _T("∃");
	else if (!_tcscmp(strNodeType, NT_PLANCKCONSTANT)) return _T("ћ");
	else if (!_tcscmp(strNodeType, NT_LIM)) return _T("lim");
	else if (!_tcscmp(strNodeType, NT_MIN)) return _T("min");
	else if (!_tcscmp(strNodeType, NT_MAX)) return _T("max");
	else if (!_tcscmp(strNodeType, NT_LIMIT)) return _T("lim");
	else if (!_tcscmp(strNodeType, NT_MINIMUM)) return _T("min");
	else if (!_tcscmp(strNodeType, NT_MAXIMUM)) return _T("max");
	else if (!_tcscmp(strNodeType, NT_LOG)) return _T("log");
	else if (!_tcscmp(strNodeType, NT_LN)) return _T("ln");
	else if (!_tcscmp(strNodeType, NT_LG)) return _T("lg");
	else if (!_tcscmp(strNodeType, NT_LOGARITHM)) return _T("log");
	else if (!_tcscmp(strNodeType, NT_NOTIN)) return _T("∉");
	else if (!_tcscmp(strNodeType, NT_NSUBSETEQ)) return _T("⊈");
	else if (!_tcscmp(strNodeType, NT_EMPTYSET)) return _T("Ø");
	else if (!_tcscmp(strNodeType, NT_LEFTRIGHTARROW)) return _T("⇔");
	else if (!_tcscmp(strNodeType, NT_MAPSTO)) return _T("↦");
	else if (!_tcscmp(strNodeType, NT_epsilon)) return _T("ϵ");
	else if (!_tcscmp(strNodeType, NT_ALEPH)) return _T("ℵ");
	else if (!_tcscmp(strNodeType, NT_varrho)) return _T("ϱ");
	else if (!_tcscmp(strNodeType, NT_BOXMINUS)) return _T("⊟");
	else if (!_tcscmp(strNodeType, NT_BOXTIMES)) return _T("⊠");
	else if (!_tcscmp(strNodeType, NT_BOXDOT)) return _T("⊡");
	else if (!_tcscmp(strNodeType, NT_BOXPLUS)) return _T("⊞");
	else if (!_tcscmp(strNodeType, NT_OMINUS)) return _T("⊖");
	else if (!_tcscmp(strNodeType, NT_CIRCLEDDASH)) return _T("⊝");
	else if (!_tcscmp(strNodeType, NT_OPLUS)) return _T("⊕");
	else if (!_tcscmp(strNodeType, NT_OTIMES)) return _T("⊗");
	else if (!_tcscmp(strNodeType, NT_OSLASH)) return _T("⊘");
	else if (!_tcscmp(strNodeType, NT_ODOT)) return _T("⊙");
	else if (!_tcscmp(strNodeType, NT_CIRCLEDCIRC)) return _T("⊚");
	else if (!_tcscmp(strNodeType, NT_CIRCLEDAST)) return _T("⊛");
	else if (!_tcscmp(strNodeType, NT_BIGODOT)) return _T("⨀");
	else if (!_tcscmp(strNodeType, NT_BIGOTIMES)) return _T("⨂");
	else if (!_tcscmp(strNodeType, NT_BIGOPLUS)) return _T("⨁");
	else if (!_tcscmp(strNodeType, NT_PARENTHESES)) return _T("()");
	else if (!_tcscmp(strNodeType, NT_BRACKETS)) return _T("[]");
	else if (!_tcscmp(strNodeType, NT_BRACES)) return _T("{}");
	else if (!_tcscmp(strNodeType, NT_ABSOLUTE)) return _T("||");
	else if (!_tcscmp(strNodeType, NT_INTEGRAL) || !_tcscmp(strNodeType, NT_INTEGRALTBLIMIT) || !_tcscmp(strNodeType, NT_INTEGRALTBSCRIPT))
		return _T("∫");
	else if (!_tcscmp(strNodeType, NT_DOUBLEINTEGRAL) || !_tcscmp(strNodeType, NT_DOUBLEINTEGRALTBLIMIT) || !_tcscmp(strNodeType, NT_DOUBLEINTEGRALTBSCRIPT))
		return _T("∬");
	else if (!_tcscmp(strNodeType, NT_TRIPLEINTEGRAL) || !_tcscmp(strNodeType, NT_TRIPLEINTEGRALTBLIMIT) || !_tcscmp(strNodeType, NT_TRIPLEINTEGRALTBSCRIPT))
		return _T("∭");
	else if (!_tcscmp(strNodeType, NT_LOOPINTEGRAL) || !_tcscmp(strNodeType, NT_LOOPINTEGRALTBLIMIT) || !_tcscmp(strNodeType, NT_LOOPINTEGRALTBSCRIPT))
		return _T("∮");
	else if (!_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRAL) || !_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRALTBLIMIT) || !_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRALTBSCRIPT))
		return _T("∯");
	else if (!_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRAL) || !_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRALTBLIMIT) || !_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRALTBSCRIPT))
		return _T("∰");
	else if (!_tcscmp(strNodeType, NT_SUM) || !_tcscmp(strNodeType, NT_SUMTBLIMIT) || !_tcscmp(strNodeType, NT_SUMTBSCRIPT) || !_tcscmp(strNodeType, NT_SUMBLIMIT) || !_tcscmp(strNodeType, NT_SUMBSCRIPT))
		return _T("∑");
	else if (!_tcscmp(strNodeType, NT_SUPREMUM) || !_tcscmp(strNodeType, NT_SUPREMUMTBLIMIT) || !_tcscmp(strNodeType, NT_SUPREMUMTBSCRIPT) || !_tcscmp(strNodeType, NT_SUPREMUMBLIMIT) || !_tcscmp(strNodeType, NT_SUPREMUMBSCRIPT))
		return _T("∨");
	else if (!_tcscmp(strNodeType, NT_INFIMUM) || !_tcscmp(strNodeType, NT_INFIMUMTBLIMIT) || !_tcscmp(strNodeType, NT_INFIMUMTBSCRIPT) || !_tcscmp(strNodeType, NT_INFIMUMBLIMIT) || !_tcscmp(strNodeType, NT_INFIMUMBSCRIPT))
		return _T("∧");
	else if (!_tcscmp(strNodeType, NT_TOPACUTEACCENT)) return _T("ˊ"); 
	else if (!_tcscmp(strNodeType, NT_TOPGRAVEACCENT)) return _T("ˋ");
	else if (!_tcscmp(strNodeType, NT_TOPCIRCUMFLEXACCENT)) return _T("ˆ");
	else if (!_tcscmp(strNodeType, NT_TOPMODULATEACCENT)) return _T("ˇ");
	else if (!_tcscmp(strNodeType, NT_TOPTILDE)) return _T("~");
	else if (!_tcscmp(strNodeType, NT_TOPBREVEACCENT)) return _T("︵");
	else if (!_tcscmp(strNodeType, NT_PRODUCT) || !_tcscmp(strNodeType, NT_PRODUCTTBLIMIT) || !_tcscmp(strNodeType, NT_PRODUCTTBSCRIPT) || !_tcscmp(strNodeType, NT_PRODUCTBLIMIT) || !_tcscmp(strNodeType, NT_PRODUCTBSCRIPT)
		|| !_tcscmp(strNodeType, NT_ACCESSORYPRODUCT) || !_tcscmp(strNodeType, NT_ACCESSORYPRODUCTTBLIMIT) || !_tcscmp(strNodeType, NT_ACCESSORYPRODUCTTBSCRIPT) || !_tcscmp(strNodeType, NT_ACCESSORYPRODUCTBLIMIT) || !_tcscmp(strNodeType, NT_ACCESSORYPRODUCTBSCRIPT))
		return _T("∏");
	else if (!_tcscmp(strNodeType, NT_UNION) || !_tcscmp(strNodeType, NT_UNIONTBLIMIT) || !_tcscmp(strNodeType, NT_UNIONTBSCRIPT) || !_tcscmp(strNodeType, NT_UNIONBLIMIT) || !_tcscmp(strNodeType, NT_UNIONBSCRIPT))
		return _T("∪");
	else if (!_tcscmp(strNodeType, NT_INTERSECTION) || !_tcscmp(strNodeType, NT_INTERSECTIONTBLIMIT) || !_tcscmp(strNodeType, NT_INTERSECTIONTBSCRIPT) || !_tcscmp(strNodeType, NT_INTERSECTIONBLIMIT) || !_tcscmp(strNodeType, NT_INTERSECTIONBSCRIPT))
		return _T("∩");
	else if (!_tcscmp(strNodeType, NT_SIN)) return _T("sin");
	else if (!_tcscmp(strNodeType, NT_COS)) return _T("cos");
	else if (!_tcscmp(strNodeType, NT_TAN)) return _T("tan");
	else if (!_tcscmp(strNodeType, NT_CSC)) return _T("csc");
	else if (!_tcscmp(strNodeType, NT_SEC)) return _T("sec");
	else if (!_tcscmp(strNodeType, NT_COT)) return _T("cot");
	else if (!_tcscmp(strNodeType, NT_ARCSIN)) return _T("arcsin");
	else if (!_tcscmp(strNodeType, NT_ARCCOS)) return _T("arccos");
	else if (!_tcscmp(strNodeType, NT_ARCTAN)) return _T("arctan");
	else if (!_tcscmp(strNodeType, NT_SINH)) return _T("sinh");
	else if (!_tcscmp(strNodeType, NT_COSH)) return _T("cosh");
	else if (!_tcscmp(strNodeType, NT_TANH)) return _T("tanh");
	else if (!_tcscmp(strNodeType, NT_COTH)) return _T("coth");
	//编译器限制：块嵌套太深
	if (!_tcscmp(strNodeType, NT_ARG)) return _T("arg");
	else if (!_tcscmp(strNodeType, NT_DEG)) return _T("deg");
	else if (!_tcscmp(strNodeType, NT_DET)) return _T("det");
	else if (!_tcscmp(strNodeType, NT_DIM)) return _T("dim");
	else if (!_tcscmp(strNodeType, NT_EXP)) return _T("exp");
	else if (!_tcscmp(strNodeType, NT_GCD)) return _T("gcd");
	else if (!_tcscmp(strNodeType, NT_HOM)) return _T("hom");
	else if (!_tcscmp(strNodeType, NT_KER)) return _T("ker");
	else if (!_tcscmp(strNodeType, NT_PR)) return _T("pr");
	else if (!_tcscmp(strNodeType, NT_LIMINF)) return _T("liminf");
	else if (!_tcscmp(strNodeType, NT_LIMSUP)) return _T("limsup");
	return _T("");
}

LPCTSTR CNode::GetFaceNameByNodeType(LPCTSTR strNodeType)
{
	const TCHAR* strFaceName = kFontFamily;
	if (!_tcscmp(strNodeType, NT_STANDARD) ||
		!_tcscmp(strNodeType, NT_INPLACE) ||
		!_tcscmp(strNodeType, NT_SUPERSCRIPT) ||
		!_tcscmp(strNodeType, NT_SUBSCRIPT) ||
		!_tcscmp(strNodeType, NT_MIDTOPBOTTOM) ||
		!_tcscmp(strNodeType, NT_TOPBOTTOMMID) ||
		!_tcscmp(strNodeType, NT_RADICAL) ||
		!_tcscmp(strNodeType, NT_PARENTHESES) ||
		!_tcscmp(strNodeType, NT_BRACKETS) ||
		!_tcscmp(strNodeType, NT_BRACES) ||
		!_tcscmp(strNodeType, NT_ABSOLUTE) ||
		!_tcscmp(strNodeType, NT_SEPARATOR) ||
		!_tcscmp(strNodeType, NT_TOPBOTTOM) ||
		!_tcscmp(strNodeType, NT_LINE) ||
		!_tcscmp(strNodeType, NT_FRACTION) ||
		!_tcscmp(strNodeType, NT_HORIZONTALMATRIX) ||
		!_tcscmp(strNodeType, NT_VERTICALMATRIX) ||
		!_tcscmp(strNodeType, NT_RIGHTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_LEFTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TWOWAYSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_RIGHTHALFARROW) ||
		!_tcscmp(strNodeType, NT_LEFTHALFARROW) ||
		!_tcscmp(strNodeType, NT_TWOWAYHALFARROW) ||
		!_tcscmp(strNodeType, NT_RIGHTDOUBLEARROW) ||
		!_tcscmp(strNodeType, NT_LEFTDOUBLEARROW) ||
		!_tcscmp(strNodeType, NT_TWOWAYDOUBLEARROW) ||
		!_tcscmp(strNodeType, NT_INVERSE))
		strFaceName = kFontFamily_Number;
	else if (!_tcscmp(strNodeType, NT_SIGN) ||
		!_tcscmp(strNodeType, NT_PLUS) ||
		!_tcscmp(strNodeType, NT_MINUS) ||
		!_tcscmp(strNodeType, NT_MULTIPLY) ||
		!_tcscmp(strNodeType, NT_DIVIDE) ||
		!_tcscmp(strNodeType, NT_EQUATION) ||
		!_tcscmp(strNodeType, NT_INTEGRAL) ||
		!_tcscmp(strNodeType, NT_DOUBLEINTEGRAL) ||
		!_tcscmp(strNodeType, NT_TRIPLEINTEGRAL) ||
		!_tcscmp(strNodeType, NT_LOOPINTEGRAL) ||
		!_tcscmp(strNodeType, NT_DOUBLELOOPINTEGRAL) ||
		!_tcscmp(strNodeType, NT_TRIPLELOOPINTEGRAL) ||
		!_tcscmp(strNodeType, NT_SUM) ||
		!_tcscmp(strNodeType, NT_SUPREMUM) ||
		!_tcscmp(strNodeType, NT_INFIMUM) ||
		!_tcscmp(strNodeType, NT_PRODUCT) ||
		!_tcscmp(strNodeType, NT_ACCESSORYPRODUCT) ||
		!_tcscmp(strNodeType, NT_UNION) ||
		!_tcscmp(strNodeType, NT_INTERSECTION))
		strFaceName = kFontFamily_Cambria;
	else if (!_tcscmp(strNodeType, NT_GREEKALPHABET))
		strFaceName = kFontFamily_GreekAlphabet;
	else if (!_tcscmp(strNodeType, NT_ALPHABET) ||
		!_tcscmp(strNodeType, NT_ALEPH) ||
		!_tcscmp(strNodeType, NT_LIM) ||
		!_tcscmp(strNodeType, NT_MIN) ||
		!_tcscmp(strNodeType, NT_MAX) ||
		!_tcscmp(strNodeType, NT_LIMIT) ||
		!_tcscmp(strNodeType, NT_MINIMUM) ||
		!_tcscmp(strNodeType, NT_MAXIMUM) ||
		!_tcscmp(strNodeType, NT_LOG) ||
		!_tcscmp(strNodeType, NT_LN) ||
		!_tcscmp(strNodeType, NT_LG) ||
		!_tcscmp(strNodeType, NT_LOGARITHM) ||
		!_tcscmp(strNodeType, NT_SIN) ||
		!_tcscmp(strNodeType, NT_COS) ||
		!_tcscmp(strNodeType, NT_TAN) ||
		!_tcscmp(strNodeType, NT_CSC) ||
		!_tcscmp(strNodeType, NT_SEC) ||
		!_tcscmp(strNodeType, NT_COT) ||
		!_tcscmp(strNodeType, NT_ARCSIN) ||
		!_tcscmp(strNodeType, NT_ARCCOS) ||
		!_tcscmp(strNodeType, NT_ARCTAN) ||
		!_tcscmp(strNodeType, NT_SINH) ||
		!_tcscmp(strNodeType, NT_COSH) ||
		!_tcscmp(strNodeType, NT_TANH) ||
		!_tcscmp(strNodeType, NT_COTH) ||
		!_tcscmp(strNodeType, NT_ARG) ||
		!_tcscmp(strNodeType, NT_DEG) ||
		!_tcscmp(strNodeType, NT_DET) ||
		!_tcscmp(strNodeType, NT_DIM) ||
		!_tcscmp(strNodeType, NT_EXP) ||
		!_tcscmp(strNodeType, NT_GCD) ||
		!_tcscmp(strNodeType, NT_HOM) ||
		!_tcscmp(strNodeType, NT_KER) ||
		!_tcscmp(strNodeType, NT_PR) ||
		!_tcscmp(strNodeType, NT_LIMINF) ||
		!_tcscmp(strNodeType, NT_LIMSUP))
		strFaceName = kFontFamily_Character;
	else if (!_tcscmp(strNodeType, NT_HANDWRITING))
		strFaceName = kFontFamily_Handwriting;
	else if (!_tcscmp(strNodeType, NT_COPPERPLATE))
		strFaceName = kFontFamily_Copperplate;
	else if (!_tcscmp(strNodeType, NT_TOPRIGHTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TOPLEFTSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TOPRIGHTHALFARROW) ||
		!_tcscmp(strNodeType, NT_TOPLEFTHALFARROW) ||
		!_tcscmp(strNodeType, NT_TOPTWOWAYSINGLEARROW) ||
		!_tcscmp(strNodeType, NT_TOPONEPOINT) ||
		!_tcscmp(strNodeType, NT_TOPTWOPOINT) ||
		!_tcscmp(strNodeType, NT_TOPTHREEPOINT) ||
		!_tcscmp(strNodeType, NT_TOPONELINE) ||
		!_tcscmp(strNodeType, NT_TOPTWOLINE) ||
		!_tcscmp(strNodeType, NT_TOPACUTEACCENT) ||
		!_tcscmp(strNodeType, NT_TOPGRAVEACCENT) ||
		!_tcscmp(strNodeType, NT_TOPCIRCUMFLEXACCENT) ||
		!_tcscmp(strNodeType, NT_TOPMODULATEACCENT) ||
		!_tcscmp(strNodeType, NT_TOPTILDE) ||
		!_tcscmp(strNodeType, NT_TOPBREVEACCENT))
		strFaceName = kFontFamily;
	else
		strFaceName = kFontFamily_Cambria;
	return strFaceName;
}

void CNode::InitTEXTMERTIC()
{
	if (!_tcscmp(m_strNodeType, NT_SUM) || !_tcscmp(m_strNodeType, NT_SUMTBLIMIT) || !_tcscmp(m_strNodeType, NT_SUMTBSCRIPT) || !_tcscmp(m_strNodeType, NT_SUMBLIMIT) || !_tcscmp(m_strNodeType, NT_SUMBSCRIPT))//∑
		m_btmInternalLeading = false;
	else if (!_tcscmp(m_strNodeType, NT_SUPREMUM) || !_tcscmp(m_strNodeType, NT_SUPREMUMTBLIMIT) || !_tcscmp(m_strNodeType, NT_SUPREMUMTBSCRIPT) || !_tcscmp(m_strNodeType, NT_SUPREMUMBLIMIT) || !_tcscmp(m_strNodeType, NT_SUPREMUMBSCRIPT)) {//∨
		m_btmInternalLeading = false;
		m_btmDescent = false;
	}
	else if (!_tcscmp(m_strNodeType, NT_INFIMUM) || !_tcscmp(m_strNodeType, NT_INFIMUMTBLIMIT) || !_tcscmp(m_strNodeType, NT_INFIMUMTBSCRIPT) || !_tcscmp(m_strNodeType, NT_INFIMUMBLIMIT) || !_tcscmp(m_strNodeType, NT_INFIMUMBSCRIPT)) {//∧
		m_btmInternalLeading = false;
		m_btmDescent = false;
	}
	else if (!_tcscmp(m_strNodeType, NT_TOPACUTEACCENT) || !_tcscmp(m_strNodeType, NT_TOPGRAVEACCENT) || !_tcscmp(m_strNodeType, NT_TOPCIRCUMFLEXACCENT) || !_tcscmp(m_strNodeType, NT_TOPMODULATEACCENT) || !_tcscmp(m_strNodeType, NT_TOPTILDE) || !_tcscmp(m_strNodeType, NT_TOPBREVEACCENT))
		m_btmInternalLeading = false;
	else if (!_tcscmp(m_strNodeType, NT_PRODUCT) || !_tcscmp(m_strNodeType, NT_PRODUCTTBLIMIT) || !_tcscmp(m_strNodeType, NT_PRODUCTTBSCRIPT) || !_tcscmp(m_strNodeType, NT_PRODUCTBLIMIT) || !_tcscmp(m_strNodeType, NT_PRODUCTBSCRIPT))//∏
		m_btmInternalLeading = false;
	else if (!_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTTBLIMIT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTTBSCRIPT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTBLIMIT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTBSCRIPT))//∏
		m_btmInternalLeading = false;
	else if (!_tcscmp(m_strNodeType, NT_UNION) || !_tcscmp(m_strNodeType, NT_UNIONTBLIMIT) || !_tcscmp(m_strNodeType, NT_UNIONTBSCRIPT) || !_tcscmp(m_strNodeType, NT_UNIONBLIMIT) || !_tcscmp(m_strNodeType, NT_UNIONBSCRIPT)) {//∪
		m_btmInternalLeading = false;
		m_btmDescent = false;
	}
	else if (!_tcscmp(m_strNodeType, NT_INTERSECTION) || !_tcscmp(m_strNodeType, NT_INTERSECTIONTBLIMIT) || !_tcscmp(m_strNodeType, NT_INTERSECTIONTBSCRIPT) || !_tcscmp(m_strNodeType, NT_INTERSECTIONBLIMIT) || !_tcscmp(m_strNodeType, NT_INTERSECTIONBSCRIPT)) {//∩
		m_btmInternalLeading = false;
		m_btmDescent = false;
	}
}

void CNode::UpdateTextSize()
{
	::ZeroMemory(&m_szText, sizeof(m_szText));
	::ZeroMemory(&m_tm, sizeof(m_tm));

	m_szText = GetTextExtent(lstrlen(m_strText) != 0 ? m_strText : _T("123"), m_lf.lfFaceName, m_iFontSize, m_btmInternalLeading, m_btmDescent);

	if (lstrlen(m_strText) == 0)
		m_szText.cx = 0;
	if (lstrlen(m_strText) == 0 && m_szText.cx < m_iMinWidth)
		m_szText.cx = m_iMinWidth;

	m_tm = GetTextMetric(m_strText, m_lf.lfFaceName, -m_lf.lfHeight, m_btmInternalLeading, m_btmDescent);
}

void CNode::UpdateRect()
{
	m_rcNode.right = m_rcNode.left + m_szText.cx;
	m_rcNode.bottom = m_rcNode.top + m_szText.cy;
	m_ptBaseline.x = m_rcNode.left;
	m_ptBaseline.y = m_rcNode.top + m_tm.tmAscent;
}

void CNode::TranslateRect(int iTranslateX, int iTranslateY)
{
	if (m_pLeftChild)
		m_pLeftChild->TranslateRect(iTranslateX, iTranslateY);
	if (m_pRightChild)
		m_pRightChild->TranslateRect(iTranslateX, iTranslateY);
	m_rcNode.left += iTranslateX;
	m_rcNode.right += iTranslateX;
	m_rcNode.top += iTranslateY;
	m_rcNode.bottom += iTranslateY;
	m_ptBaseline.x += iTranslateX;
	m_ptBaseline.y += iTranslateY;
}

void CNode::TranslateChildRectToTopLeft()
{
	m_rcNode.left = m_rcNode.top = 0;
	int offsetX = 0, offsetY = 0;
	if (m_pLeftChild) {
		offsetX = m_rcNode.left - m_pLeftChild->m_rcNode.left;
		offsetY = m_rcNode.top - m_pLeftChild->m_rcNode.top;
		m_pLeftChild->TranslateRect(offsetX, offsetY);
	}
	if (m_pRightChild) {
		offsetX = m_rcNode.left - m_pRightChild->m_rcNode.left;
		offsetY = m_rcNode.top - m_pRightChild->m_rcNode.top;
		m_pRightChild->TranslateRect(offsetX, offsetY);
	}
}

void CNode::UpdateNodeBorder()
{
	if (m_pLeftChild && m_pRightChild) {
		m_rcNode.left = min(m_pLeftChild->m_rcNode.left, m_pRightChild->m_rcNode.left);
		m_rcNode.right = max(m_pLeftChild->m_rcNode.right, m_pRightChild->m_rcNode.right);
		m_rcNode.top = min(m_pLeftChild->m_rcNode.top, m_pRightChild->m_rcNode.top);
		m_rcNode.bottom = max(m_pLeftChild->m_rcNode.bottom, m_pRightChild->m_rcNode.bottom);
	}
}

void CNode::ExtendBorderByChild()
{
	//TODO
}

CNode* CNode::GetMatrixRootNode()
{
	CNode* pNode = m_pParent;

	while (pNode && _tcscmp(pNode->m_strNodeType, NT_VERTICALMATRIX) && _tcscmp(pNode->m_strNodeType, NT_HORIZONTALMATRIX))
		pNode = pNode->m_pParent;

	while (pNode && pNode->m_pParent && (!_tcscmp(pNode->m_pParent->m_strNodeType, NT_VERTICALMATRIX) || !_tcscmp(pNode->m_pParent->m_strNodeType, NT_HORIZONTALMATRIX)))
		pNode = pNode->m_pParent;

	if (pNode && _tcscmp(pNode->m_strNodeType, NT_VERTICALMATRIX) && _tcscmp(pNode->m_strNodeType, NT_HORIZONTALMATRIX))
		pNode = NULL;

	return pNode;
}

int CNode::GetMatrixRows()
{
	return 0;
}

int CNode::GetMatrixColumn()
{
	return 0;
}

void CNode::FormatMatrixRect()
{
	//TODO
}

// draw the node pre-order 
// first myself
// second the left child 
// third the right child
void CNode::DrawNode(Gdiplus::Graphics* pGraphics)
{
	DrawNodeText(pGraphics, m_ptBaseline);
	
	//显示节点区域边框
	DrawNodeRegion(pGraphics);
}

void CNode::DrawNodeText(Gdiplus::Graphics* pGraphics, POINT pt)
{
	//gdi
	HDC hdc = pGraphics->GetHDC();

	if (lstrlen(m_strText)) {
		if (m_btmInternalLeading && m_btmDescent) {
			HFONT hFont = CreateFontIndirect(&m_lf);
			HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
			SetTextColor(hdc, m_crColor);
			SetBkMode(hdc, TRANSPARENT);
			TextOut(hdc, pt.x, pt.y - m_tm.tmAscent, m_strText, lstrlen(m_strText));

			SelectObject(hdc, hOldFont);
			//::DeleteObject(hOldFont);
			::DeleteObject(hFont);
		}
		else {
			TEXTMETRIC tm = GetTextMetric(m_strText, m_lf.lfFaceName, m_iFontSize, m_btmInternalLeading, m_btmDescent);
			if (!_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTTBLIMIT) ||
				!_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTTBSCRIPT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTBLIMIT) || !_tcscmp(m_strNodeType, NT_ACCESSORYPRODUCTBSCRIPT)) {
				HDC hDcMem = CreateCompatibleDC(hdc);
				HBITMAP hBmp = CreateCompatibleBitmap(hdc, m_szText.cx, tm.tmHeight);
				HGDIOBJ hOld = SelectObject(hDcMem, hBmp);

				//SetBkMode(hDcMem, TRANSPARENT);
				::SetBkColor(hDcMem, RGB(255, 255, 255));

				LOGFONT lf = m_lf;
				lf.lfHeight = 0 - m_iFontSize;
				HFONT hFont = CreateFontIndirect(&lf);
				HFONT hOldFont = (HFONT)SelectObject(hDcMem, hFont);
				//SetBkMode(hDcMem, TRANSPARENT);
				SetTextColor(hDcMem, m_crColor);
				TextOut(hDcMem, 0, 0, m_strText, lstrlen(m_strText));

				::StretchBlt(hdc, pt.x, pt.y - m_tm.tmAscent + 4, m_szText.cx, tm.tmHeight, hDcMem, 0, tm.tmHeight, m_szText.cx, -tm.tmHeight, SRCCOPY);//上下翻转

				::SelectObject(hDcMem, hOldFont);
				//::DeleteObject(hOldFont);
				::DeleteObject(hFont);

				::SelectObject(hDcMem, hOld);
				::DeleteObject(hBmp);
				::DeleteDC(hDcMem);
			}
			else {
				LOGFONT lf = m_lf;
				lf.lfHeight = 0 - m_iFontSize;
				HFONT hFont = CreateFontIndirect(&lf);
				HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
				SetTextColor(hdc, m_crColor);
				SetBkMode(hdc, TRANSPARENT);
				TextOut(hdc, pt.x, pt.y - m_tm.tmAscent - tm.tmInternalLeading, m_strText, lstrlen(m_strText));

				SelectObject(hdc, hOldFont);
				//::DeleteObject(hOldFont);
				::DeleteObject(hFont);
			}
		}
	}

	pGraphics->ReleaseHDC(hdc);

	//gdi+
	//Font font(m_lf.lfFaceName, GetFontSize(), FontStyleRegular, UnitPixel);
	//SolidBrush brush(RGBToARGB(255, m_crColor));
	//pGraphics->DrawString(m_strText, lstrlen(m_strText), &font, PointF(pt.x, pt.y), &brush);
}

void CNode::DrawNodeRegion(Gdiplus::Graphics* pGraphics, bool bShowBorder)
{
	bool bShowNodeRegion = false;
	if (bShowBorder)
		bShowNodeRegion = true;
	else {
#ifdef SHOW_NODE_REGION
		bShowNodeRegion = true;
#else
		if (!_tcscmp(m_strNodeType, NT_STANDARD) && lstrlen(m_strText) == 0 && GetWidth() > 2)
			bShowNodeRegion = true;
#endif
	}
	if (bShowNodeRegion) {
		//gdi
		HDC hdc = pGraphics->GetHDC();

		HPEN hPen = CreatePen(PS_DOT, 0, m_crColor);
		HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
		HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
		HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
		Rectangle(hdc, m_rcNode.left, m_rcNode.top, m_rcNode.right, m_rcNode.bottom);
		SelectObject(hdc, hOldBrush);
		DeleteObject(hBrush);
		SelectObject(hdc, hOldPen);
		DeleteObject(hPen);

		pGraphics->ReleaseHDC(hdc);

		//gdi+
		//Pen pen(RGBToARGB(255, m_crColor), 1.5f);
		//pen.SetDashStyle(DashStyleDot);
		//pGraphics->DrawRectangle(&pen, m_rcNode.left, m_rcNode.top, m_rcNode.right - m_rcNode.left, m_rcNode.bottom - m_rcNode.top);
	}
}

void CNode::DrawLine(Gdiplus::Graphics* pGraphics, POINT pt1, POINT pt2, UINT iPenWidth)
{
	HDC hdc = pGraphics->GetHDC();

	HPEN hPen = CreatePen(PS_SOLID, iPenWidth, m_crColor);
	HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);

	MoveToEx(hdc, pt1.x, pt1.y, NULL);
	LineTo(hdc, pt2.x, pt2.y);

	SelectObject(hdc, hOldPen);
	DeleteObject(hPen);

	pGraphics->ReleaseHDC(hdc);
}

void CNode::DrawArrow(Gdiplus::Graphics* pGraphics, POINT pt1, POINT pt2, double theta, int length, float fPenWidth, COLORREF crColor, bool bTop, bool bBottom)
{
    Gdiplus::Pen pen(crColor, fPenWidth);

	POINT pt3, pt4;
	pt3 = PlaneVectorRotate(pt2, pt1, theta, length);
	pt4 = PlaneVectorRotate(pt2, pt1, -theta, length);

	pGraphics->DrawLine(&pen, pt1.x, pt1.y, pt2.x, pt2.y);

	double delta = sqrt((pt2.x - pt1.x) * (pt2.x - pt1.x) + (pt2.y - pt1.y) * (pt2.y - pt1.y));
	double dlength = length * cos(3.1415926 * theta / 180);
	if (delta >= dlength) {
		if (bTop)
			pGraphics->DrawLine(&pen, pt2.x, pt2.y, pt3.x, pt3.y);
		if (bBottom)
			pGraphics->DrawLine(&pen, pt2.x, pt2.y, pt4.x, pt4.y);
	}
}

void CNode::DrawDoubleArrow(Gdiplus::Graphics* pGraphics, POINT pt1, POINT pt2, double theta, int length, int offset, float fPenWidth, COLORREF crColor)
{
    Gdiplus::Pen pen(crColor, fPenWidth);

	POINT pt3, pt4, pt5, pt6, pt7, pt8, pt9;

	pt3 = PlaneVectorRotate(pt1, pt2, -90, offset);
	pt5 = PlaneVectorRotate(pt1, pt2, 90, offset);

	pt4 = pt3;
	pt4.x += pt2.x - pt1.x;
	pt6 = pt5;
	pt6.x += pt2.x - pt1.x;

	LONG dx = round(offset / tan(3.1415926 * theta / 180));
	pt9 = PlaneVectorRotate(pt2, pt1, 3.1415926, -dx);

	pt7 = PlaneVectorRotate(pt9, pt4, 0, length);
	pt8 = PlaneVectorRotate(pt9, pt6, 0, length);

	pGraphics->DrawLine(&pen, pt3.x, pt3.y, pt4.x, pt4.y);
	pGraphics->DrawLine(&pen, pt5.x, pt5.y, pt6.x, pt6.y);

	double delta = sqrt((pt2.x - pt1.x) * (pt2.x - pt1.x) + (pt2.y - pt1.y) * (pt2.y - pt1.y));
	double dlength = length * cos(3.1415926 * theta / 180);
	if (delta >= dlength) {
		pGraphics->DrawLine(&pen, pt9.x, pt9.y, pt7.x, pt7.y);
		pGraphics->DrawLine(&pen, pt9.x, pt9.y, pt8.x, pt8.y);
	}
}

CNode* CNode::GetNodeFromPoint(POINT pt)
{
	// do hittest and normalize hit
	int nHandle = HitTest(pt);
	if (nHandle == hitMiddle)
		return this;
	else if (nHandle == hitLeftChild)
		return m_pLeftChild->GetNodeFromPoint(pt);
	else if (nHandle == hitRightChild)
		return m_pRightChild->GetNodeFromPoint(pt);
	else
		return NULL;
}

CNode* CNode::GetLeftJointNode(bool bDelMode)
{
	CNode* pRes = NULL;
	CNode* pNode = NULL;

	pNode = m_pParent;
	while (pNode) {
		if (!pNode->m_bDelMode && !bDelMode)
			return NULL;
		CNode* pTmp = GetRightEditNode(pNode->m_pLeftChild, bDelMode);
		if (pTmp && pTmp != this && pTmp->GetRect().left < m_rcNode.left) {
			pRes = pTmp;
			break;
		}
		else
			pNode = pNode->m_pParent;
	}

	return pRes;
}

CNode* CNode::GetRightJointNode(bool bDelMode)
{
	CNode* pRes = NULL;
	CNode* pNode = NULL;

	pNode = m_pParent;
	while (pNode) {
		CNode* pTmp = GetLeftEditNode(pNode->m_pRightChild, bDelMode);
		if (pTmp && pTmp != this && pTmp->GetRect().right > m_rcNode.right) {
			pRes = pTmp;
			break;
		}
		else
			pNode = pNode->m_pParent;
	}

	return pRes;
}

CNode* CNode::GetLeftEditNode(CNode* pNode, bool bDelMode)
{
	CNode* pRes = NULL;
	if (pNode) {
		if (!_tcscmp(pNode->m_strNodeType, NT_STANDARD)) {
			pRes = pNode;
			return pRes;
		}
		if (!pNode->m_bDelMode && !bDelMode)
			return NULL;
		pRes = GetLeftEditNode(pNode->m_pLeftChild, bDelMode);
		if (pRes)
			return pRes;
		pRes = GetLeftEditNode(pNode->m_pRightChild, bDelMode);
		if (pRes)
			return pRes;
	}
	return pRes;
}

CNode* CNode::GetRightEditNode(CNode* pNode, bool bDelMode)
{
	CNode* pRes = NULL;
	if (pNode) {
		if (!_tcscmp(pNode->m_strNodeType, NT_STANDARD)) {
			pRes = pNode;
			return pRes;
		}
		if (!pNode->m_bDelMode && !bDelMode)
			return NULL;
		pRes = GetRightEditNode(pNode->m_pRightChild, bDelMode);
		if (pRes)
			return pRes;
		pRes = GetRightEditNode(pNode->m_pLeftChild, bDelMode);
		if (pRes)
			return pRes;
	}
	return pRes;
}

CNode* CNode::GetFarLeftChild()
{
	CNode* pRes = this;

	while (pRes->m_pLeftChild)
		pRes = pRes->m_pLeftChild;

	return pRes;
}

CNode* CNode::GetFarRightChild()
{
	CNode* pRes = this;

	while (pRes->m_pRightChild)
		pRes = pRes->m_pRightChild;

	return pRes;
}

CNode* CNode::GetDelNode()
{
	CNode* pRes = NULL;

	if (!m_pParent) return pRes;

	if (m_pParent->m_pRightChild == this) {
		if (m_pParent && m_pParent->m_pLeftChild && m_pParent->m_pLeftChild->m_pRightChild)
			pRes = m_pParent->m_pLeftChild->m_pRightChild;
	}
	else if (m_pParent->m_pLeftChild == this) {
		CNode* pNode = m_pParent;
		while (pNode && pNode->GetFarLeftChild() == this)
			pNode = pNode->m_pParent;

		if (pNode && pNode->m_pLeftChild && pNode->m_pLeftChild->m_pRightChild)
			pRes = pNode->m_pLeftChild->m_pRightChild;
	}

	if (pRes && pRes->m_bDelMode)
		pRes = NULL;

	return pRes;
}

int CNode::HitTest(POINT point)
{
	TrackerHit hitResult = hitNothing;

	if (m_pLeftChild && PtInRect(&m_pLeftChild->GetRect(), point))
		hitResult = hitLeftChild;
	else if (m_pRightChild && PtInRect(&m_pRightChild->GetRect(), point))
		hitResult = hitRightChild;
	else if (!_tcscmp(m_strNodeType, NT_STANDARD))// && PtInRect(&m_rcNode, point)
		hitResult = hitMiddle;

	return hitResult;
}

void CNode::save(LPTSTR strFormulaText)
{
	if (IsLeftChild()) _tcscat(strFormulaText, _T("\"L\""));
	if (IsRightChild()) _tcscat(strFormulaText, _T("\"R\""));
	_tcscat(strFormulaText, _T("\\"));
	_tcscat(strFormulaText, m_strNodeType);
	_tcscat(strFormulaText, _T("{"));
	if (m_pLeftChild)
		m_pLeftChild->save(strFormulaText);
	if (m_pRightChild)
		m_pRightChild->save(strFormulaText);
	_tcscat(strFormulaText, _T("}"));
}

CNode* CNode::load(LPCTSTR strFormulaText)
{
	CNode* pNode = NULL;
	if (_tcsstr(strFormulaText, _T("\\NT_"))) {
		int iLength = 0;
		const TCHAR* strtok1 = _tcschr(strFormulaText, _T('{'));
		iLength = _tcslen(strFormulaText) - _tcslen(strtok1) - 1;
		TCHAR* strNodeType = new TCHAR[iLength + 1];
		_tcsncpy(strNodeType, strFormulaText + 1, iLength);
		strNodeType[iLength] = 0;

		const TCHAR* strtok2 = _tcsrchr(strFormulaText, _T('}'));
		iLength = _tcslen(strtok1) - _tcslen(strtok2) - 1;
		TCHAR* strText = new TCHAR[iLength + 1];
		_tcsncpy(strText, strtok1 + 1, iLength);
		strText[iLength] = 0;

		if (!_tcscmp(strNodeType, NT_STANDARD))
			pNode = dynamicCreateNode(strNodeType, strText);
		else {
			CNode *pLeftChild = NULL;
			CNode *pRightChild = NULL;
			TCHAR strText2[MAX_PATH];
			TCHAR strDirection[24];//左孩子还是右孩子，用于只有一个孩子的情况
			::ZeroMemory(strText2, sizeof(strText2));
			::ZeroMemory(strDirection, sizeof(strDirection));
			const TCHAR* strtok3 = _tcsstr(strText, _T("\\NT_"));
			if (_tcslen(strText) > _tcslen(strtok3))
				_tcsncpy(strText2, strText, _tcslen(strText) - _tcslen(strtok3));
			//取节点文字内容和左孩子右孩子的方向
			if (_tcslen(strText2)) {
				const TCHAR* strtokDirection = _tcsstr(strText2, _T("\""));
				if (strtokDirection) {
					TCHAR strText3[MAX_PATH];
					::ZeroMemory(strText3, sizeof(strText3));
					_tcsncpy(strText3, strText2, _tcslen(strText2) - _tcslen(strtokDirection));
					_tcscpy(strDirection, strtokDirection);
					_tcscpy(strText2, strText3);
				}
			}
			pNode = dynamicCreateNode(strNodeType, strText2);

			if (const TCHAR* strtok4 = _tcsrstr_Braces(strtok3 + 1, _T("\\NT_"))) {
				iLength = _tcslen(strtok3) - _tcslen(strtok4);
				TCHAR* strNodeText = new TCHAR[iLength + 1];
				_tcsncpy(strNodeText, strtok3, iLength);
				strNodeText[iLength] = 0;

				pLeftChild = load(strNodeText);
				pNode->SetLeftChild(pLeftChild);
				pRightChild = load(strtok4);
				pNode->SetRightChild(pRightChild);
				delete[] strNodeText;
			}
			else {
				if (!_tcscmp(strDirection, _T("\"L\""))) {
					pLeftChild = load(strtok3);
					pNode->SetLeftChild(pLeftChild);
				}
				else if (!_tcscmp(strDirection, _T("\"R\""))) {
					pRightChild = load(strtok3);
					pNode->SetRightChild(pRightChild);
				}
			}
		}
		delete[] strText;
		delete[] strNodeType;
	}
	return pNode;
}
